package par

import (
	"errors"
	"strconv"
	"strings"

	"gitcode.com/deyiyangyang/gascheme/ast"
	"gitcode.com/deyiyangyang/gascheme/lex"
	"gitcode.com/deyiyangyang/gascheme/tok"
)

// Parser represents a parser for Scheme expressions
type Parser struct {
	lexer        *lex.Lexer
	currentToken tok.Token
	peekToken    tok.Token
}

// NewParser creates a new parser
func NewParser(lexer *lex.Lexer) *Parser {
	p := &Parser{lexer: lexer}
	// Read two tokens so that currentToken and peekToken are both set
	p.nextToken()
	p.nextToken()
	return p
}

// nextToken advances the current token
func (p *Parser) nextToken() {
	p.currentToken = p.peekToken
	p.peekToken = p.lexer.NextToken()
}

func (p *Parser) Parse() ([]ast.Expression, error) {
	es := []ast.Expression{}
	for p.currentToken.Type != tok.EOF {
		e, err := p.ParseExpression()
		if err != nil {
			return nil, err
		}
		es = append(es, e)
		p.nextToken()
	}
	return es, nil
}

// ParseExpression parses an expression
func (p *Parser) ParseExpression() (ast.Expression, error) {
	// If we've reached EOF, return nil
	if p.currentToken.Type == tok.EOF {
		return nil, nil
	}

	switch p.currentToken.Type {
	case tok.LPAREN:
		return p.parseListExpression()
	case tok.INT:
		return p.parseIntegerLiteral()
	case tok.RATIONAL:
		return p.parseRationalLiteral()
	case tok.REAL:
		return p.parseRealLiteral()
	case tok.SYMBOL:
		return p.parseSymbolLiteral()
	case tok.BOOLEAN:
		return p.parseBooleanLiteral()
	case tok.CHAR:
		return p.parseCharacterLiteral()
	case tok.STRING:
		return p.parseStringLiteral()
	case tok.QUOTE:
		// Handle quote syntax: 'expr => (quote expr)
		token := p.currentToken
		p.nextToken() // consume '
		expr, err := p.ParseExpression()
		if err != nil {
			return nil, err
		}
		// Create a list expression: (quote expr)
		list := &ast.ListExpression{Token: token}
		list.Elements = []ast.Expression{
			&ast.SymbolLiteral{Token: tok.Token{Type: tok.SYMBOL, Lexeme: "quote"}, Value: "quote"},
			expr,
		}
		return list, nil
	}
	return nil, errors.New("unknown expression type: " + string(p.currentToken.Type))
}

// parseStringLiteral parses a string literal
func (p *Parser) parseStringLiteral() (*ast.StringLiteral, error) {
	lit := &ast.StringLiteral{Token: p.currentToken}
	lexeme := p.currentToken.Lexeme

	// 处理转义字符
	var processed strings.Builder
	for i := 0; i < len(lexeme); i++ {
		if lexeme[i] == '\\' && i+1 < len(lexeme) {
			// 处理转义字符
			switch lexeme[i+1] {
			case '"':
				processed.WriteByte('"')
				i++ // 跳过下一个字符
			case '\\':
				processed.WriteByte('\\')
				i++ // 跳过下一个字符
			default:
				// 如果不是已知的转义字符，保留原样
				processed.WriteByte(lexeme[i])
			}
		} else {
			// 普通字符
			processed.WriteByte(lexeme[i])
		}
	}

	lit.Value = processed.String()

	// 不再在这里调用nextToken，让调用者处理
	return lit, nil
}

// parseCharacterLiteral parses a character literal
func (p *Parser) parseCharacterLiteral() (*ast.CharacterLiteral, error) {
	lit := &ast.CharacterLiteral{Token: p.currentToken}
	lexeme := p.currentToken.Lexeme

	// Character literals have the format #\x where x is a character
	// Special cases: #\space, #\newline
	if len(lexeme) < 2 {
		return nil, errors.New("invalid character literal: " + lexeme)
	}

	// Remove the #\ prefix
	charStr := lexeme[2:]

	// Handle special character names
	switch charStr {
	case "space":
		lit.Value = ' '
	case "newline":
		lit.Value = '\n'
	case "tab":
		lit.Value = '\t'
	default:
		// For single characters, just use the character itself
		if len(charStr) == 1 {
			lit.Value = rune(charStr[0])
		} else {
			return nil, errors.New("invalid character literal: " + lexeme)
		}
	}

	return lit, nil
}

// parseBooleanLiteral parses a boolean literal
func (p *Parser) parseBooleanLiteral() (*ast.BooleanLiteral, error) {
	lit := &ast.BooleanLiteral{Token: p.currentToken}

	// Check if the literal is #t (true) or #f (false)
	if p.currentToken.Lexeme == "#t" {
		lit.Value = true
	} else if p.currentToken.Lexeme == "#f" {
		lit.Value = false
	} else {
		return nil, errors.New("invalid boolean literal: " + p.currentToken.Lexeme)
	}

	return lit, nil
}

// parseListExpression parses a list expression
func (p *Parser) parseListExpression() (*ast.ListExpression, error) {
	list := &ast.ListExpression{Token: p.currentToken}
	list.Elements = []ast.Expression{}

	// Consume the LPAREN
	p.nextToken()

	// Parse elements until we hit RPAREN
	for p.currentToken.Type != tok.RPAREN && p.currentToken.Type != tok.EOF {
		expr, err := p.ParseExpression()
		if err != nil {
			return nil, err
		}
		list.Elements = append(list.Elements, expr)
		p.nextToken()
	}

	// Make sure we have a closing RPAREN
	if p.currentToken.Type != tok.RPAREN {
		return nil, errors.New("expected ')' after list expression")
	}

	return list, nil
}

// parseIntegerLiteral parses an integer literal
func (p *Parser) parseIntegerLiteral() (*ast.IntegerLiteral, error) {
	lit := &ast.IntegerLiteral{Token: p.currentToken}

	value, err := strconv.ParseInt(p.currentToken.Lexeme, 0, 64)
	if err != nil {
		return nil, errors.New("could not parse " + p.currentToken.Lexeme + " as integer")
	}

	lit.Value = value
	return lit, nil
}

// parseRationalLiteral parses a rational number literal
func (p *Parser) parseRationalLiteral() (*ast.RationalLiteral, error) {
	lit := &ast.RationalLiteral{Token: p.currentToken}

	// Split the lexeme into numerator and denominator
	parts := strings.Split(p.currentToken.Lexeme, "/")
	if len(parts) != 2 {
		return nil, errors.New("invalid rational number format: " + p.currentToken.Lexeme)
	}

	// Parse numerator
	numerator, err := strconv.ParseInt(parts[0], 0, 64)
	if err != nil {
		return nil, errors.New("could not parse numerator " + parts[0] + " as integer")
	}

	// Parse denominator
	denominator, err := strconv.ParseInt(parts[1], 0, 64)
	if err != nil {
		return nil, errors.New("could not parse denominator " + parts[1] + " as integer")
	}

	// Check for division by zero
	if denominator == 0 {
		return nil, errors.New("division by zero in rational number")
	}

	lit.Numerator = numerator
	lit.Denominator = denominator
	return lit, nil
}

// parseRealLiteral parses a real number literal
func (p *Parser) parseRealLiteral() (*ast.RealLiteral, error) {
	lit := &ast.RealLiteral{Token: p.currentToken}

	value, err := strconv.ParseFloat(p.currentToken.Lexeme, 64)
	if err != nil {
		return nil, errors.New("could not parse " + p.currentToken.Lexeme + " as real number")
	}

	lit.Value = value
	return lit, nil
}

// parseSymbolLiteral parses a symbol literal
func (p *Parser) parseSymbolLiteral() (*ast.SymbolLiteral, error) {
	return &ast.SymbolLiteral{
		Token: p.currentToken,
		Value: p.currentToken.Lexeme,
	}, nil
}
